require "utils"
require "pm"
require "pins"
require "tool"
require "aLiCMD"
require "hwCMD"
require "hwIotda"
-- require "YaLiCMD"

module(..., package.seeall)

-------------------------------------------- 配置串口 --------------------------------------------
-- 保持系统处于唤醒状态，不会休眠
pm.wake("485_uart")
-- 485芯片相关设置
pmd.ldoset(15, pmd.LDO_VMMC)

local cmd_buf
-- 串口ID,串口读缓冲区
local uart_id = 2
local test_state = 0
local send_state = 0

local login = {}
local logout = {}

-- 流量计读数
local liuliang = 0
local off_state = false

local data_list = {
    temp_buf = "",
    hum_buf = "",
    co2_buf = "",
    nh3_buf = "",
    cur_buf = "",
    state = "",
    out_temp = "",
    out_hum = "",
    elc_num = -99
}

local temp_list = {
    temp_buf = "",
    hum_buf = "",
    co2_buf = "",
    nh3_buf = "",
    cur_buf = "",
    state = "",
    out_temp = "",
    out_hum = "",
    elc_num = -99
}

local clean_list = {
    temp_buf = "",
    hum_buf = "",
    co2_buf = "",
    nh3_buf = "",
    cur_buf = "",
    state = "",
    out_temp = "",
    out_hum = "",
    elc_num = -99
}



-- 判断地址是否在列表中
local function addrNotInList(list, addr)
    for i, data in ipairs(list) do
        if data.addr == addr then
            return false
        end
    end
    return true
end

-- 往列表中添加数据
local function dataAdd(value, type, addr)
    value = tostring(value)
    if type == "T" then
        data_list.temp_buf = data_list.temp_buf .. value .. ","
    end

    if type == "H" then
        data_list.hum_buf = data_list.hum_buf .. value .. ","
    end

    if type == "CO2" then
        data_list.co2_buf = data_list.co2_buf .. value .. ","
    end

    if type == "NH3" then
        data_list.nh3_buf = value
    end

    if type == "CUR" and addr == "01" then
        data_list.cur_buf = value
    elseif type == "CUR" and addr == "02" then
        data_list.cur_buf = data_list.cur_buf .. "," .. value
    end

    if type == "STA" and addr == "01" then
        data_list.state = value
    elseif type == "STA" and addr == "02" then
        data_list.state = data_list.state .. "," .. value
    end

    if type == "TO" then
        data_list.out_temp = value
    end

    if type == "HO" then
        data_list.out_hum = value
    end

    if type == "ELC" then
        data_list.elc_num = tonumber(value)
    end
end

-- 往列表中添加地址 
local function addrAdd()
    data_list = tool.deepCopy(clean_list)
    local addr_list = tool.deepCopy(nvm.get("DEV_SUB_ADDR"))
    for i, data in ipairs(addr_list) do
        if addrNotInList(data_list, data) then
            for ii, vv in ipairs(data_list) do
                if data_list[ii].addr == "" then
                    data_list[ii].addr = data
                    break
                end
            end
        end
    end

end

-- modbus 命令返回CRC校验处理
local function checkmodbus(data)
    if string.len(data) < 3 then
        log.warn("MODBUS", "Data is too short")
        return false
    end
    -- 校验读回来的包是否整个crc正确
    if pack.pack('<H', crypto.crc16("MODBUS", string.sub(data, 1, -3))):toHex() ~=
            string.sub(data, -2):toHex() then
        log.warn("MODBUS", "CRC error")
        return false
    end

    return true
end

-- 根据子设备类型设置串口参数
function init_uart()
    uart.close(uart_id)
    local baud = nvm.get("DEV_SUB_BAUD")
    local par = nvm.get("DEV_SUB_PARITY")
    uart.setup(uart_id, baud, 8, par, uart.STOP_1)
    uart.set_rs485_oe(uart_id, pio.P0_24, 1, 1, 1, nil,
            1)
    uart.on(uart_id, "receive", function()
        sys.publish("UART_RECEIVE")
    end)

end

-- 485读取
local function modbusRead()
    local cacheData = ""
    while true do
        local s = uart.read(uart_id, 1)
        if s == "" then
            if not sys.waitUntil("UART_RECEIVE", 10) then
                if cacheData:len() > 0 then
                    sys.publish("MY_UART_REC_DAT", cacheData)
                    log.info("RECEIVE", string.toHex(cacheData),
                            #string.toHex(cacheData))
                    -- aLiCMD.eventPost(string.toHex(cacheData))
                    cacheData = ""
                end
            end
            sys.wait(10) -- 这里一定要延时，否则会死机
        else
            cacheData = cacheData .. s
        end
    end
end

-- 启动串口数据接收任务
sys.taskInit(modbusRead)


-- 力夫温湿度度探头
local function handleLFTemp(address)
    local addr = address
    local modbus_data = string.fromHex(addr .. "0300010002")
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
            "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)

    result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
    if result == true then
        if checkmodbus(cmd_buf) == true and addr ==
                string.sub(string.toHex(cmd_buf), 1, 2) then
            cmd_buf = string.toHex(cmd_buf)
            log.info("UART 485 GET:", cmd_buf, #cmd_buf)
            local data = tonumber(string.sub(cmd_buf, 7, 10), 16) / 10
            local hum = tonumber(string.sub(cmd_buf, 11, 14), 16) / 10
            sys.publish("GET_485_DATA", addr .. "|" .. data .. " C " .. hum .. " %")
            dataAdd(data, "T")
            dataAdd(hum, "H")
            -- 阿里云数据推送
            -- aLiCMD.dataPost(tostring(data), cmd_buf)
            -- YaLiCMD.dataPost(tostring(data), cmd_buf, true)
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd("-999", "T")
            dataAdd("-999", "H")
        end
    else
        sys.publish("GET_485_DATA", addr .. "|" .. "---")
        dataAdd("-888", "T")
        dataAdd("-888", "H")
    end
end

-- 力夫温室外湿度度探头
local function handleLFTempOut(address)
    local addr = address
    local modbus_data = string.fromHex(addr .. "0300010002")
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
            "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)

    result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
    if result == true then
        if checkmodbus(cmd_buf) == true and addr ==
                string.sub(string.toHex(cmd_buf), 1, 2) then
            cmd_buf = string.toHex(cmd_buf)
            log.info("UART 485 GET:", cmd_buf, #cmd_buf)
            local data = tonumber(string.sub(cmd_buf, 7, 10), 16) / 10
            local hum = tonumber(string.sub(cmd_buf, 11, 14), 16) / 10
            sys.publish("GET_485_DATA", addr .. "|" .. data .. " C " .. hum .. " %")
            dataAdd(data, "TO")
            dataAdd(hum, "HO")
            -- 阿里云数据推送
            -- aLiCMD.dataPost(tostring(data), cmd_buf)
            -- YaLiCMD.dataPost(tostring(data), cmd_buf, true)
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd("-999", "TO")
            dataAdd("-999", "HO")
        end
    else
        sys.publish("GET_485_DATA", addr .. "|" .. "---")
        dataAdd("-888", "TO")
        dataAdd("-888", "HO")
    end
end

-- 力夫二氧化碳探头
local function handleLFCO2(address)
    local addr = address
    local modbus_data = string.fromHex(addr .. "0300020003")
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
            "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)

    result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
    if result == true then
        if checkmodbus(cmd_buf) == true and addr ==
                string.sub(string.toHex(cmd_buf), 1, 2) then
            cmd_buf = string.toHex(cmd_buf)
            log.info("UART 485 GET:", cmd_buf, #cmd_buf)
            local data = tonumber(string.sub(cmd_buf, 7, 10), 16)

            sys.publish("GET_485_DATA", addr .. "|" .. data .. " ppm")
            dataAdd(data, "CO2")
            -- 阿里云数据推送
            -- aLiCMD.dataPost(tostring(data), cmd_buf)
            -- YaLiCMD.dataPost(tostring(data), cmd_buf, true)
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd("-999", "CO2")
        end
    else
        sys.publish("GET_485_DATA", addr .. "|" .. "---")
        dataAdd("-888", "CO2")
    end
end

local alarm_list = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
local alarm_state_list = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }

-- 判断风机状态
local function handleFan(addr, cur_list)
    local under_cur = tool.deepCopy(nvm.get("FAN_UNDER_CUR"))
    local over_cur = tool.deepCopy(nvm.get("FAN_OVER_CUR"))
    local under_list = {}
    local over_list = {}

    --默认欠流电流
    if #under_cur == 0 then
        under_cur = { "01|1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000",
                      "02|1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000" }
    end
    --默认过流电流
    if #over_cur == 0 then
        over_cur = { "01|6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000",
                     "02|6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000,6000" }
    end
    --获取每一路电流的配置
    if #under_cur > 0 then
        for i, v in ipairs(under_cur) do
            if v ~= nil and tool.Split(v, "|")[1] == addr then
                local res = tool.Split(v, "|")[2]
                under_list = tool.Split(res, ",")
            end
        end
    end

    if #over_cur > 0 then
        for i, v in ipairs(over_cur) do
            if v ~= nil and tool.Split(v, "|")[1] == addr then
                local res = tool.Split(v, "|")[2]
                over_list = tool.Split(res, ",")
            end
        end
    end

    local state = {}
    if #cur_list == 16 and #under_list == 16 and #over_list == 16 then
        for i, v in ipairs(cur_list) do
            -- 判断风机开启、关闭状态
            if tonumber(v) > tonumber(under_list[i]) and tonumber(v) < tonumber(over_list[i]) then
                table.insert(state, 1)
            else
                table.insert(state, 0)
            end

            if tonumber(v) > nvm.get("FAN_IND_CUR") and tonumber(v) < tonumber(under_list[i]) then
                alarm_list[i] = alarm_list[i] + 1
                if alarm_list[i] > 10 and (alarm_state_list[i] == 0 or alarm_state_list[i] == -1) then
                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
                            "FAN_ALARM_" .. addr .. "_" .. i,
                            "LOW#NOW_" .. tonumber(v) .. ',SET_' .. tonumber(under_list[i]),
                            0)
                    if hwIotda.isReady() then
                        alarm_list[i] = 0
                        alarm_state_list[i] = 1
                    end
                end
            end

            if tonumber(v) > nvm.get("FAN_IND_CUR") and tonumber(v) > tonumber(over_list[i]) then
                alarm_list[i] = alarm_list[i] + 1
                if alarm_list[i] > 10 and (alarm_state_list[i] == 0 or alarm_state_list[i] == -1) then
                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
                            "FAN_ALARM_" .. addr .. "_" .. i,
                            "HIGH#NOW_" .. tonumber(v) .. ',SET_' .. tonumber(over_list[i]),
                            0)
                    if hwIotda.isReady() then
                        alarm_list[i] = 0
                        alarm_state_list[i] = 1
                    end
                end
            end

            if tonumber(v) > nvm.get("FAN_IND_CUR") and tonumber(v) < tonumber(over_list[i])
                    and tonumber(v) > tonumber(under_list[i]) then
                if alarm_list[i] > 0 then
                    alarm_list[i] = 0
                end

                if alarm_state_list[i] == 1 then
                    alarm_list[i] = alarm_list[i] - 1
                end

                if alarm_list[i] < -10 and (alarm_state_list[i] == 1 or alarm_state_list[i] == -1) then
                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
                            "FAN_ALARM_" .. addr .. "_" .. i,
                            "RECOVERY#NOW_" .. tonumber(v) .. ',SET_' .. tonumber(under_list[i]) .. '-' .. tonumber(over_list[i]),
                            1)
                    if hwIotda.isReady() then
                        alarm_list[i] = 0
                        alarm_state_list[i] = 0
                    end
                end
            end
        end
    end

    if #state == 16 then
        dataAdd(table.concat(state, ","), "STA")
        log.info("STA", table.concat(state, ","))
    end
end

local function indCur(data)
    if data < nvm.get("FAN_IND_CUR") then
        return 0
    else
        return data
    end
end

local function toBits(num)
    -- 返回一个包含二进制位的表格，最低位在最前面。
    local t = {} -- 将包含这些二进制位
    if num == 0 then
        return { 0, 0, 0, 0, 0, 0, 0, 0 }
    end
    while num > 0 do
        rest = math.fmod(num, 2)
        t[#t + 1] = rest
        num = (num - rest) / 2
    end
    while #t < 8 do
        table.insert(t, 0)
    end
    return t
end

-- RSD-16|FAN
local function handleRSD16(address)
    local addr = address

    local modbus_data = string.fromHex(addr .. "03 01 00 00 01")
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
            "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)

    result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
    if result == true then
        if checkmodbus(cmd_buf) == true and addr == string.sub(string.toHex(cmd_buf), 1, 2) then
            cmd_buf = string.toHex(cmd_buf)
            local a1 = tonumber(string.sub(cmd_buf, 7, 8), 16)
            local a2 = tonumber(string.sub(cmd_buf, 9, 10), 16)
            local a1_b = toBits(a1)
            local a2_b = toBits(a2)
            log.info("UART 485 GET STATE:", cmd_buf, #cmd_buf)
            log.info("FAN STATE:", table.concat(a1_b, ","))
            log.info("FAN STATE:", table.concat(a2_b, ","))

            dataAdd(table.concat(a2_b, ",") .. ',' .. table.concat(a1_b, ","), "STA", addr)
        end
    end

    modbus_data = string.fromHex(addr .. "03 01 07 00 10")
    modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
            "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)

    result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
    if result == true then
        if checkmodbus(cmd_buf) == true and addr ==
                string.sub(string.toHex(cmd_buf), 1, 2) and #string.toHex(cmd_buf) > 70 then
            cmd_buf = string.toHex(cmd_buf)
            log.info("UART 485 GET:", cmd_buf, #cmd_buf)
            local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16
            local index = tonumber(addr)
            local rate_list = { 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000 }
            local rate_org = tool.deepCopy(nvm.get("FAN_RATE"))

            for i, v in ipairs(rate_org) do
                if v ~= nil and tool.Split(v, "|")[1] == addr then
                    local res = tool.Split(v, "|")[2]
                    rate_list = tool.Split(res, ",")
                end
            end

            if #rate_list == 16 then
                a1 = indCur(tonumber(string.sub(cmd_buf, 7, 10), 16) / 10000 * rate_list[1])
                a2 = indCur(tonumber(string.sub(cmd_buf, 11, 14), 16) / 10000 * rate_list[2])
                a3 = indCur(tonumber(string.sub(cmd_buf, 15, 18), 16) / 10000 * rate_list[3])
                a4 = indCur(tonumber(string.sub(cmd_buf, 19, 22), 16) / 10000 * rate_list[4])
                a5 = indCur(tonumber(string.sub(cmd_buf, 23, 26), 16) / 10000 * rate_list[5])
                a6 = indCur(tonumber(string.sub(cmd_buf, 27, 30), 16) / 10000 * rate_list[6])
                a7 = indCur(tonumber(string.sub(cmd_buf, 31, 34), 16) / 10000 * rate_list[7])
                a8 = indCur(tonumber(string.sub(cmd_buf, 35, 38), 16) / 10000 * rate_list[8])
                a9 = indCur(tonumber(string.sub(cmd_buf, 39, 42), 16) / 10000 * rate_list[9])
                a10 = indCur(tonumber(string.sub(cmd_buf, 43, 46), 16) / 10000 * rate_list[10])
                a11 = indCur(tonumber(string.sub(cmd_buf, 47, 50), 16) / 10000 * rate_list[11])
                a12 = indCur(tonumber(string.sub(cmd_buf, 51, 54), 16) / 10000 * rate_list[12])
                a13 = indCur(tonumber(string.sub(cmd_buf, 55, 58), 16) / 10000 * rate_list[13])
                a14 = indCur(tonumber(string.sub(cmd_buf, 59, 62), 16) / 10000 * rate_list[14])
                a15 = indCur(tonumber(string.sub(cmd_buf, 63, 66), 16) / 10000 * rate_list[15])
                a16 = indCur(tonumber(string.sub(cmd_buf, 67, 70), 16) / 10000 * rate_list[16])
            end
            local data = a1 .. "," .. a2 .. "," .. a3 .. "," .. a4 .. "," .. a5 .. "," .. a6 .. "," .. a7 .. "," .. a8
                    .. "," .. a9 .. "," .. a10 .. "," .. a11 .. "," .. a12 .. "," .. a13 .. "," .. a14 .. "," .. a15 .. "," .. a16
            log.info("CUR", data)
            --handleFan(address, tool.Split(data, ","))
            sys.publish("GET_485_DATA", addr .. "|" .. string.format("%.1f", a1 / 1000) .. ' '
                    .. string.format("%.1f", a2 / 1000) .. ' '
                    .. string.format("%.1f", a3 / 1000) .. " A")
            dataAdd(data, "CUR", addr)
            -- 阿里云数据推送
            -- aLiCMD.dataPost(tostring(data), cmd_buf)
            -- YaLiCMD.dataPost(tostring(data), cmd_buf, true)
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd("-999", "CUR")

        end
    else
        sys.publish("GET_485_DATA", addr .. "|" .. "---")
        dataAdd("-888", "CUR")
    end
end

-- 对接三菱变频器
local function handleMitsubishi(address)
    sys.taskInit(function()
        local addr = address
        local modbus_data = string.fromHex(addr .. "03 00 C8 00 01")
        local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
        local modbus_crc_data = pack.pack('<H', modbus_crc_value)
        log.info("Uart send ",
                "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
        uart.write(uart_id, modbus_data .. modbus_crc_data)

        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
        if result == true then
            if checkmodbus(cmd_buf) == true and addr ==
                    string.sub(string.toHex(cmd_buf), 1, 2) then
                cmd_buf = string.toHex(cmd_buf)
                log.info("UART 485 GET:", cmd_buf, #cmd_buf)
                local data = tonumber(string.sub(cmd_buf, 7, 10), 16) / 100

                addr = string.sub(cmd_buf, 1, 2)
                sys.publish("GET_485_DATA", addr .. "|" .. data)
                dataAdd(addr, { data })
            else
                sys.publish("GET_485_DATA", addr .. "|" .. "---")
                dataAdd(addr, { -9999 })
            end
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd(addr, { -8888 })
        end
    end)
end

-- 对接派诺电表
local function handlePaiNuo(address)
    sys.taskInit(function()
        local addr = address
        local modbus_data = string.fromHex(addr .. "03 00 00 00 0F")
        local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
        local modbus_crc_data = pack.pack('<H', modbus_crc_value)
        log.info("Uart send ",
                "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
        uart.write(uart_id, modbus_data .. modbus_crc_data)

        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
        if result == true then
            if checkmodbus(cmd_buf) == true and addr ==
                    string.sub(string.toHex(cmd_buf), 1, 2) and #string.toHex(cmd_buf) > 62 then
                cmd_buf = string.toHex(cmd_buf)
                log.info("UART 485 GET:", cmd_buf, #cmd_buf)
                local a_v = tonumber(string.sub(cmd_buf, 7, 10), 16) / 100
                local b_v = tonumber(string.sub(cmd_buf, 11, 14), 16) / 100
                local c_v = tonumber(string.sub(cmd_buf, 15, 18), 16) / 100
                local a_i = tonumber(string.sub(cmd_buf, 23, 26) ..
                        string.sub(cmd_buf, 19, 22), 16) / 1000
                local b_i = tonumber(string.sub(cmd_buf, 31, 34) ..
                        string.sub(cmd_buf, 27, 30), 16) / 1000
                local c_i = tonumber(string.sub(cmd_buf, 39, 42) ..
                        string.sub(cmd_buf, 35, 38), 16) / 1000
                local data = tonumber(string.sub(cmd_buf, 63, 66) ..
                        string.sub(cmd_buf, 59, 62), 16) / 10

                log.info("I hex", string.sub(cmd_buf, 23, 26) ..
                        string.sub(cmd_buf, 19, 22), string.sub(cmd_buf,
                        31, 34) ..
                        string.sub(cmd_buf, 27, 30), string.sub(cmd_buf,
                        39, 42) ..
                        string.sub(cmd_buf, 35, 38))
                addr = string.sub(cmd_buf, 1, 2)
                sys.publish("GET_485_DATA", addr .. "|" .. data .. " kWh")

                dataAdd(data, "ELC")
            else
                sys.publish("GET_485_DATA", addr .. "|" .. "---")
                dataAdd(-99, "ELC")
            end
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd(-88, "ELC")
        end
    end)
end

-- 对接国标电表
local function handleDT2Y545(address)
    sys.taskInit(function()
        local addr = address
        local modbus_data = string.fromHex(
                "FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 33 33 33 AD 16")
        log.info("Uart send ", "msg: " .. string.toHex(modbus_data))
        uart.write(uart_id, modbus_data)

        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
        -- result = true

        if result == true then

            cmd_buf = string.toHex(cmd_buf)

            -- aLiCMD.eventPost(cmd_buf)
            local s, e = string.find(cmd_buf, "68")
            cmd_buf = string.sub(cmd_buf, s, -1)
            log.info("UART 485 GET:", cmd_buf, #cmd_buf)

            if string.sub(cmd_buf, 39, 40) == "16" and #cmd_buf > 39 then
                local data = {}
                data[1] = string.gsub(string.format("%#x", tonumber(
                        string.sub(cmd_buf, 29,
                                30), 16) - 51),
                        "0x", "")
                data[1] = string.gsub(data[1], " ", "")
                data[2] = string.gsub(string.format("%#x", tonumber(
                        string.sub(cmd_buf, 31,
                                32), 16) - 51),
                        "0x", "")
                data[2] = string.gsub(data[2], " ", "")
                data[3] = string.gsub(string.format("%#x", tonumber(
                        string.sub(cmd_buf, 33,
                                34), 16) - 51),
                        "0x", "")
                data[3] = string.gsub(data[3], " ", "")
                data[4] = string.gsub(string.format("%#x", tonumber(
                        string.sub(cmd_buf, 35,
                                36), 16) - 51),
                        "0x", "")
                data[4] = string.gsub(data[4], " ", "")

                if tonumber(data[1]) < 10 then
                    data[1] = "0" .. data[1]
                end
                if tonumber(data[2]) < 10 then
                    data[2] = "0" .. data[2]
                end
                if tonumber(data[3]) < 10 then
                    data[3] = "0" .. data[3]
                end
                if tonumber(data[4]) < 10 then
                    data[4] = "0" .. data[4]
                end

                log.info("TO NUMBER DATA", data[4], data[3], data[2], data[1])
                local res = tonumber(data[4] .. data[3] .. data[2] .. data[1])
                log.info("DATA", string.sub(cmd_buf, 29, 36), res)
                sys.publish("GET_485_DATA", addr .. "|" .. data)
                dataAdd(addr, { res })
                -- table.insert(data_list, {res})
            else
                sys.publish("GET_485_DATA", addr .. "|" .. "---")
                dataAdd(addr, { -9999 })
            end
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd(addr, { -8888 })
        end
    end)
end

-- 南京水门水表
local function handleNanjing(address)
    sys.taskInit(function()
        -- 带上地址码
        local addr = address
        local modbus_data = string.fromHex(addr .. "03 00 00 00 04")
        local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
        local modbus_crc_data = pack.pack('<H', modbus_crc_value)
        log.info("Uart send ",
                "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
        uart.write(uart_id, modbus_data .. modbus_crc_data)

        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 1000)

        if result == true then
            if checkmodbus(cmd_buf) == true then
                cmd_buf = string.toHex(cmd_buf)
                log.info("UART 485 GET:", cmd_buf, #cmd_buf)
                local data = tonumber(string.sub(cmd_buf, 7, 14), 10) / 10000
                sys.publish("GET_485_DATA", addr .. "|" .. data)

                sys.publish("handleNanjing")
                dataAdd(addr, { data })
            else
                sys.publish("GET_485_DATA", addr .. "|" .. "---")
                dataAdd(addr, { -9999 })
            end
        else
            sys.publish("GET_485_DATA", addr .. "|" .. "---")
            dataAdd(addr, { -8888 })
        end

    end)
end

-- 即时发送一条485设备信息查询
function testDevice(type)
    sys.taskInit(function()
        test_state = 1
        log.info("testDevice")
        local addr_list = tool.deepCopy(nvm.get("DEV_SUB_ADDR"))
        local dev_list = tool.deepCopy(nvm.get("DEV_SUB_TYPE"))
        data_list = tool.deepCopy(clean_list)
        addrAdd()
        sys.wait(200)
        data_list = tool.deepCopy(clean_list)
        if #addr_list > 0 then
            for i, data in ipairs(addr_list) do
                if dev_list[i] == "DFPM93|E" then
                    handlePaiNuo(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "NJSM" then
                    handleNanjing(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "MITSUBISHI|F" then
                    handleMitsubishi(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFH10|TH" then
                    handleLFTemp(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFH52|THO" then
                    handleLFTempOut(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFG201|CO2" then
                    handleLFCO2(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "RSD-16|FAN" then
                    handleRSD16(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                end
            end
        end

        test_state = 0
    end)
end

-- MQTT485命令发送
function mqttSend(str, topic, type)
    sys.taskInit(function()
        local data = string.fromHex(str)
        uart.write(uart_id, data)
        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)

        local r_topic = string.gsub(topic, "request", "response")
        local re = {}
        if result then
            re["code"] = 200
            re["message"] = "success"
            re["data"] = {}
            re["data"]["cmdResult"] = "Send:" .. str .. ",Rec:" ..
                    string.toHex(cmd_buf)
        else
            re["code"] = 400
            re["message"] = "fail"
        end

        re["id"] = tool.miscTime()
        re["version"] = "1.0"
        if type == "L" then
            aLiOutMsg.aLiInstertMsg(r_topic, re)
        end
    end)
end

-- MQTT485命令发送
function hwMqttSend(str, topic)
    sys.taskInit(function()
        local data = string.fromHex(str)
        uart.write(uart_id, data)
        result, cmd_buf = sys.waitUntil("MY_UART_REC_DAT", 800)
        local re = {}
        if result then
            re["result_code"] = 0
            re["paras"] = {
                ["data"] = "Send:" .. str .. ",Rec:" .. string.toHex(cmd_buf)
            }
        else
            re["result_code"] = 0
            re["paras"] = { ["data"] = "No Rec Data" }
        end

        local res = tool.Split(topic, "/")

        hwOutMsg.hwInstertMsg("$oc/devices/" .. config.HW_DEV_PRODUCTID ..
                "_GWEV_" .. misc.getImei() ..
                "/sys/commands/response/" .. res[6], re)
    end)
end

-- 设置波特率
function set485_baud(str, topic, type)
    sys.taskInit(function()
        local now = nvm.get("DEV_BAUD")
        nvm.set("DEV_BAUD", tonumber(str))
        local r_topic = string.gsub(topic, "request", "response")
        local re = {}
        re["code"] = 200
        re["message"] = "success"
        re["data"] = {}
        re["data"]["cmdResult"] = "Baud Now:" .. now .. ",Baud Set:" .. str

        re["id"] = tool.miscTime()
        re["version"] = "1.0"

        if type == "L" then
            aLiOutMsg.aLiInstertMsg(r_topic, re)
        elseif type == "Y" then
            -- YaLiOutMsg.aLiInstertMsg(r_topic, re)
        end

        init_uart()
    end)
end

-- 设置地址码
function set485_addr(str, topic, type)
    local now = nvm.get("DEV_ADDR")
    nvm.set("DEV_ADDR", str)

    local r_topic = string.gsub(topic, "request", "response")
    local re = {}
    re["code"] = 200
    re["message"] = "success"
    re["data"] = {}
    re["data"]["cmdResult"] = "Addr Now:" .. now .. ",Addr Set:" .. str

    re["id"] = tool.miscTime()
    re["version"] = "1.0"

    if type == "L" then
        aLiOutMsg.aLiInstertMsg(r_topic, re)
    elseif type == "Y" then
        -- YaLiOutMsg.aLiInstertMsg(r_topic, re)
    end

    init_uart()
end

-- 设置485设备类型
function set485_type(str, topic, type)
    local now = nvm.get("DEV_SUB_TYPE")
    -- nvm.set("DEV_SUB_TYPE", str)
    -- -- mqttOutMsg.mqttInsertMsg(config.MQTT_TOPIC3, misc.getImei() .. ",Type now:" .. now .. ",Type Set:" .. str)
    -- deviceConfig.testDevice(0)

    local r_topic = string.gsub(topic, "request", "response")
    local re = {}
    re["code"] = 200
    re["message"] = "success"
    re["data"] = {}
    re["data"]["cmdResult"] = "Type Now:" .. now .. ",Type Set:" .. str

    re["id"] = tool.miscTime()
    re["version"] = "1.0"

    if type == "L" then
        aLiOutMsg.aLiInstertMsg(r_topic, re)
    elseif type == "Y" then
        -- YaLiOutMsg.aLiInstertMsg(r_topic, re)
    end

    tool.setHWType(str)
end

-- 设置校验位
function set485_even(str, topic, type)
    sys.taskInit(function()
        local now = nvm.get("DEV_PARITY")

        if str == "N" then
            nvm.set("DEV_PARITY", uart.PAR_NONE)
        elseif str == "E" then
            nvm.set("DEV_PARITY", uart.PAR_EVEN)
        elseif str == "O" then
            nvm.set("DEV_PARITY", uart.PAR_ODD)
        end

        local r_topic = string.gsub(topic, "request", "response")
        local re = {}
        re["code"] = 200
        re["message"] = "success"
        re["data"] = {}
        re["data"]["cmdResult"] = "Even Set:" .. str

        re["id"] = tool.miscTime()
        re["version"] = "1.0"

        if type == "L" then
            aLiOutMsg.aLiInstertMsg(r_topic, re)
        elseif type == "Y" then
            -- YaLiOutMsg.aLiInstertMsg(r_topic, re)
        end
        init_uart()
    end)
end

-- 设置采样时间间隔
function set485_time(str, topic, type)
    local now = nvm.get("DEV_TIME")
    nvm.set("DEV_TIME", tonumber(str))

    local r_topic = string.gsub(topic, "request", "response")
    local re = {}
    re["code"] = 200
    re["message"] = "success"
    re["data"] = {}
    re["data"]["cmdResult"] = "Time Now:" .. now .. ",Time Set:" .. str

    re["id"] = tool.miscTime()
    re["version"] = "1.0"

    if type == "L" then
        aLiOutMsg.aLiInstertMsg(r_topic, re)
    elseif type == "Y" then
        -- YaLiOutMsg.aLiInstertMsg(r_topic, re)
    end
end

sys.taskInit(function()
    sys.wait(200)
    while true do
        local addr_list = tool.deepCopy(nvm.get("DEV_SUB_ADDR"))
        local dev_list = tool.deepCopy(nvm.get("DEV_SUB_TYPE"))
        data_list = tool.deepCopy(clean_list)
        if #addr_list > 0 and test_state == 0 then
            send_state = 1
            addrAdd()
            init_uart()
            for i, data in ipairs(addr_list) do
                if dev_list[i] == "DFPM93|E" then
                    handlePaiNuo(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "NJSM" then
                    handleNanjing(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "MITSUBISHI|F" then
                    handleMitsubishi(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFH10|TH" then
                    handleLFTemp(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFH52|THO" then
                    handleLFTempOut(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "LFG201|CO2" then
                    handleLFCO2(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                elseif dev_list[i] == "RSD-16|FAN" then
                    handleRSD16(data)
                    sys.waitUntil("GET_485_DATA", 1000)
                end
            end

        end

        temp_list = tool.deepCopy(data_list)

        -- 每3s读取一次数据
        sys.wait(3000)
        send_state = 0
        --log.info("MEM free size", 1024 - collectgarbage("count"))
        collectgarbage("collect")

    end
end)

--定时上传数据
sys.taskInit(function()
    init_uart()
    while true do
        --log.info("TIME UPLOAD", hwIotda.isReady())
        if hwIotda.isReady() == true and (#temp_list.temp_buf > 0 or #temp_list.hum_buf > 0 or #temp_list.nh3_buf > 0
                or #temp_list.co2_buf > 0 or #temp_list.state > 0 or #temp_list.cur_buf > 0 or #temp_list.out_hum > 0
                or #temp_list.out_temp > 0) then
            hwCMD.subsetLogin(config.HW_ENV_PRODUCT_KEY, string.sub(misc.getImei(), -6, -1) .. "_ENV")
            hwCMD.dataPostEnv(temp_list)
        end

        if hwIotda.isReady() == true and temp_list.elc_num >= 0 then
            hwCMD.subsetLogin(config.HW_ELECT_PRODUCT_KEY, string.sub(misc.getImei(), -6, -1) .. "_ELC")
            hwCMD.dataPostElc(temp_list.elc_num)
        else
            hwCMD.subsetLogout(config.HW_ELECT_PRODUCT_KEY, string.sub(misc.getImei(), -6, -1) .. "_ELC")
        end
        sys.wait(nvm.get("DEV_TIME") * 1000)
    end
end)

-- 告警任务
--sys.taskInit(function()
--    sys.waitUntil("HW_MQTT_READY", 300000)
--    local temp_count = 0
--    local hum_count = 0
--    local co2_count = 0
--
--    while true do
--        local temp_sum = 0
--        local temp_avg = 0
--
--        local hum_sum = 0
--        local hum_avg = 0
--
--        local co2_sum = 0
--        local co2_avg = 0
--
--        -- 平均温度以及报警部分
--        if #temp_list.temp_buf > 0 then
--            local temp = tool.Split(temp_list.temp_buf, ",")
--            for i, v in ipairs(temp) do
--                if i < #temp then
--                    if tonumber(v) > 0 then
--                        temp_sum = temp_sum + tonumber(v)
--                    end
--                end
--            end
--            log.info("AVG TEMP", temp_sum / (#temp - 1))
--            temp_avg = temp_sum / (#temp - 1)
--            if temp_avg > 0 and temp_avg > nvm.get("TEMP_OVER") and (nvm.get("TEMP_STATE") == false or nvm.get("TEMP_STATE") == nil) then
--                temp_count = temp_count + 1
--                if temp_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "TEMPERATURE_ALARM",
--                            "HIGH#NOW_" .. temp_avg .. ',SET_' .. nvm.get("TEMP_OVER"),
--                            0)
--                    if hwIotda.isReady() then
--                        nvm.set("TEMP_STATE", true)
--                        temp_count = 0
--                    end
--                end
--            elseif temp_avg > 0 and temp_avg < nvm.get("TEMP_UNDER") and (nvm.get("TEMP_STATE") == false or nvm.get("TEMP_STATE") == nil) then
--                temp_count = temp_count + 1
--                if temp_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "TEMPERATURE_ALARM",
--                            "LOW#NOW_" .. temp_avg .. ',SET_' .. nvm.get("TEMP_UNDER"),
--                            0)
--                    if hwIotda.isReady() then
--                        nvm.set("TEMP_STATE", true)
--                        temp_count = 0
--                    end
--                end
--            elseif temp_avg > 0 and temp_avg > nvm.get("TEMP_UNDER") and temp_avg < nvm.get("TEMP_OVER") and (nvm.get("TEMP_STATE") == true or nvm.get("TEMP_STATE") == nil) then
--                temp_count = temp_count + 1
--                if temp_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "TEMPERATURE_ALARM",
--                            "RECOVERY#NOW_" .. temp_avg .. ',' .. ",SET_" .. nvm.get("TEMP_UNDER") .. '-' .. nvm.get("TEMP_OVER"),
--                            1)
--                    if hwIotda.isReady() then
--                        nvm.set("TEMP_STATE", false)
--                        temp_count = 0
--                    end
--
--                end
--            end
--        end
--
--        if #temp_list.hum_buf > 0 then
--            local hum = tool.Split(temp_list.hum_buf, ",")
--            for i, v in ipairs(hum) do
--                if i < #hum then
--                    if tonumber(v) > 0 then
--                        hum_sum = hum_sum + tonumber(v)
--                    end
--                end
--            end
--            log.info("AVG HUM", hum_sum / (#hum - 1))
--            hum_avg = hum_sum / (#hum - 1)
--
--            if hum_avg > 0 and hum_avg > nvm.get("HUM_OVER") and (nvm.get("HUM_STATE") == false or nvm.get("HUM_STATE") == nil) then
--                hum_count = hum_count + 1
--                if hum_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "HUMIDITY_ALARM",
--                            "HIGH#NOW_" .. hum_avg .. ',SET_' .. nvm.get("HUM_OVER"),
--                            0)
--                    if hwIotda.isReady() then
--                        nvm.set("HUM_STATE", true)
--                        hum_count = 0
--                    end
--                end
--            elseif hum_avg > 0 and hum_avg < nvm.get("HUM_UNDER") and (nvm.get("HUM_STATE") == false or nvm.get("HUM_STATE") == nil) then
--                hum_count = hum_count + 1
--                if hum_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "HUMIDITY_ALARM",
--                            "LOW#NOW_" .. hum_avg .. ',SET_' .. nvm.get("HUM_UNDER"),
--                            0)
--                    if hwIotda.isReady() then
--                        nvm.set("HUM_STATE", true)
--                        hum_count = 0
--                    end
--                end
--            elseif hum_avg > 0 and hum_avg > nvm.get("HUM_UNDER") and hum_avg < nvm.get("HUM_OVER") and (nvm.get("HUM_STATE") == true or nvm.get("HUM_STATE") == nil) then
--                hum_count = hum_count + 1
--                if hum_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "HUMIDITY_ALARM",
--                            "RECOVERY#NOW_" .. hum_avg .. ',SET_' .. nvm.get("HUM_UNDER") .. '-' .. nvm.get("HUM_OVER"),
--                            1)
--                    if hwIotda.isReady() then
--                        hum_count = 0
--                        nvm.set("HUM_STATE", false)
--                    end
--
--                end
--            end
--        end
--
--        if #temp_list.co2_buf > 0 then
--            local co2 = tool.Split(temp_list.co2_buf, ",")
--            for i, v in ipairs(co2) do
--                if i < #co2 then
--                    if tonumber(v) > 0 then
--                        co2_sum = co2_sum + tonumber(v)
--                    end
--                end
--            end
--            log.info("AVG CO2", co2_sum / (#co2 - 1))
--            co2_avg = co2_sum / (#co2 - 1)
--
--            if co2_avg > 0 and co2_avg > nvm.get("CO2_OVER") and (nvm.get("CO2_STATE") == false or nvm.get("CO2_STATE") == nil) then
--                co2_count = co2_count + 1
--                if co2_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "CO2_ALARM",
--                            "HIGH#NOW_" .. co2_avg .. ',SET_' .. nvm.get("CO2_OVER"),
--                            0)
--                    if hwIotda.isReady() then
--                        nvm.set("CO2_STATE", true)
--                        co2_count = 0
--                    end
--                end
--            elseif co2_avg > 0 and co2_avg < nvm.get("CO2_OVER") and (nvm.get("CO2_STATE") == true or nvm.get("CO2_STATE") == nil) then
--                co2_count = co2_count + 1
--                if co2_count > 6 then
--                    hwCMD.hwAlarm(config.HW_ENV_PRODUCT_KEY .. "_" .. string.sub(misc.getImei(), -6, -1) .. "_ENV",
--                            "CO2_ALARM",
--                            "RECOVERY#NOW_" .. co2_avg .. ',SET_' .. nvm.get("CO2_OVER"),
--                            1)
--                    if hwIotda.isReady() then
--                        co2_count = 0
--                        nvm.set("CO2_STATE", false)
--                    end
--
--                end
--            end
--        end
--
--        sys.wait(5000)
--    end
--end)

-- 出厂测试，自动发送返回
function factoryTest()
    uart.write(uart_id, "#LINKTA#")
end

function factoryTestTask(data)
    if data == "#LINKTA#" then
        uart.write(uart_id, "@LINKTA@")
    end
end

-- 每天晚上10:30网关自动重启
function daliyReboot()
    sys.taskInit(function()
        sys.wait(65000)
        if nvm.get("RANDOM_NUM") == nil or nvm.get("RANDOM_NUM") == 0 then
            math.randomseed(os.time())
            local num = math.random(1, 40)
            nvm.set("RANDOM_NUM", num)
        end
        local num = nvm.get("RANDOM_NUM")
        while true do
            local t = misc.getClock()
            if t["hour"] == 22 and t["min"] == 10 + num then
                sys.restart("TIME to REBOOT!!")
            end
            sys.wait(10000)
        end
    end)
end

sys.subscribe("MY_UART_REC_DAT", factoryTestTask)

